![](/img/trans.png)
[英]How can I pass method as function parameter without 'lambda' keyword?
[英]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.