簡體   English   中英

如何將對象屬性作為函數參數傳遞給lambda函數?

[英]How can I pass an object attribute to lambda function, as function parameter?

我創建了兩個返回已排序列表的函數。 它們都作為參數列出了包含Employee Class實例的列表。 第一個按名稱屬性排序,第二個按年齡排序,兩者都使用lambda函數

class Employee():

    allEmployees = []

    def __init__(self, name, age):
        self.name = name
        self.age = age
        Employee.allEmployees.append(self)


def sortEmployeesByName(some_list, name):
    return sorted(some_list, key=lambda employee: employee.name)

def sortEmployeesByAge(some_list, age):
    return sorted(some_list, key=lambda employee: employee.age)

如何只創建一個函數sortEmployees ,我將該屬性作為第二個參數傳遞並使用lambda函數?

例如

def sortEmployess(some_list, attribute):
    return sorted(some_list, key=lambda employee: employee.attribute)

你想要operator.attrgetter ,不需要lambdas。 這也應該更好:

sorted(some_list, key=operator.attrgetter('name'))

使用operator.attrgeter 我添加了__repr__方法來查看示例:

from operator import attrgetter

class Employee:

    allEmployees = []

    def __init__(self, name, age):
        self.name = name
        self.age = age
        Employee.allEmployees.append(self)

    def __repr__(self):
        return f'Employee({self.name}, {self.age})'

def sortEmployees(some_list, attribute):
    f = attrgetter(attribute)
    return sorted(some_list, key=f)

l = [Employee('John', 30),
Employee('Miranda', 20),
Employee('Paolo', 42)]

print(sortEmployees(Employee.allEmployees, 'name'))
print(sortEmployees(Employee.allEmployees, 'age'))

打印:

[Employee(John, 30), Employee(Miranda, 20), Employee(Paolo, 42)]
[Employee(Miranda, 20), Employee(John, 30), Employee(Paolo, 42)]

這是使用operator.attrgetter的另一個版本。 我認為在這里給Employee類一個.sort 類方法是有意義的。 我已經“借用”了__repr__方法並測試了Andrej Kesely的數據。 ;)

from operator import attrgetter

class Employee:
    allEmployees = []

    def __init__(self, name, age):
        self.name = name
        self.age = age
        Employee.allEmployees.append(self)

    def __repr__(self):
        return f'Employee({self.name}, {self.age})'

    @classmethod
    def sort(cls, attr):
        return sorted(cls.allEmployees, key=attrgetter(attr))   

Employee('John', 30)
Employee('Miranda', 20)
Employee('Paolo', 42)

print(Employee.sort('name'))
print(Employee.sort('age'))

產量

[Employee(John, 30), Employee(Miranda, 20), Employee(Paolo, 42)]
[Employee(Miranda, 20), Employee(John, 30), Employee(Paolo, 42)]

關於operator.attrgetter一個好處是我們可以傳遞多個屬性,它將返回一個屬性元組。 我們可以使用它在一次傳遞中按多個屬性進行排序。 但我們需要稍微修改.sort方法。 其他代碼保持不變。

    @classmethod
    def sort(cls, *attrs):
        return sorted(cls.allEmployees, key=attrgetter(*attrs))


Employee('John', 30)
Employee('Miranda', 20)
Employee('Paolo', 42)
Employee('John', 20)

print(Employee.sort('name'))
print(Employee.sort('age'))
print(Employee.sort('name', 'age'))

產量

[Employee(John, 30), Employee(John, 20), Employee(Miranda, 20), Employee(Paolo, 42)]
[Employee(Miranda, 20), Employee(John, 20), Employee(John, 30), Employee(Paolo, 42)]
[Employee(John, 20), Employee(John, 30), Employee(Miranda, 20), Employee(Paolo, 42)]

你可能不想這樣做,但我會告訴你如何使用getattr

getattr(object, name[, default])

返回object的named屬性的 name必須是一個字符串。 如果字符串是對象屬性之一的名稱,則結果是該屬性的值。 例如, getattr(x, 'foobar')等同於x.foobar 如果named屬性不存在,則返回default (如果提供),否則引發AttributeError

所以:

def sortEmployees(some_list, age, key_attr):
    return sorted(some_list, key=lambda employee: getattr(employee, key_attr))

但是,如果你使用它的唯一的東西是一個排序鍵,stdlib中的attrgetter包裝了你,所以你不需要lambda你自己的函數:

def sortEmployees(some_list, age, key_attr):
    return sorted(some_list, key=operator.attrgetter(key_attr))

您可能不想這樣做的原因是混合數據和變量名稱通常是一個壞主意, 正如Ned Batchelder所解釋的那樣。

你最終得到的東西看起來像人類讀者,你的IDE,以及靜態跳棋,如短頭和類型檢查器,甚至可能是類似優化器的動態代碼,即使它實際上做的只是靜態的。 您將獲得動態代碼的所有缺點而沒有任何好處。

你甚至沒有得到更短的方法調用:

sortEmployeesByName(some_list, name)
sortEmployees(some_list, name, "name")

然而,這只是“可能”而不是“絕對”的原因是,在某些情況下,相同的權衡取向相反。

例如,如果您有15個這樣的屬性而不是2個,復制和粘貼以及編輯代碼15次將是一次嚴重的DRY違規。 或者,假設您正在動態構建類或其實例,並且直到運行時才知道名稱。

當然,您可以編寫在類或實例創建時動態生成方法的代碼,以便可以通過客戶端代碼靜態使用它們。 這是一個很好的模式(在stdlib的各個地方使用)。 但對於一個死的簡單案例,它可能會使事情過於復雜。 (一個典型的讀者可以明白getattr比計算出一個setattr和一個描述符__get__調用手動綁定一個方法更容易意味着什么。)它仍然無法幫助許多靜態工具理解你的類型的方法。

在許多這樣的情況下,修復它的方法是停止具有單獨的命名屬性,而是具有單個屬性,該屬性是包含所有非完全屬性的事物的dict。 但同樣,這只是“很多”,而不是“全部”,而權衡可以走另一條路。 例如,ORM類或類似於Pandas DataFrame的東西,您希望能夠作為屬性訪問屬性。

所以,這就是為什么這個功能存在的原因:因為有時你需要它。 在這種情況下,我認為你確實不需要它,但這是一個判斷。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM