从该类中获取给定类的装饰方法

时间:2018-02-06 11:01:33

标签: python

给定一个类及其一组方法 - 如何从该类中确定哪些方法已使用某个装饰器进行了装饰?

我的目标是基本上获取装饰方法的实际值,例如:

class A():
    def get_values(self):
      ... 
      # returned {'a-special-name': 1, 'b': 2}


    @my_dec('a-special-name')  # Ideally be able to also put optional name
    def a(self):
      return 1

    @my_dec
    def b(self):
      return 2

关于如何做到这一点的任何想法?

编辑:这也应该适用于父类,也就是说,如果A是以下的子类:

class B():
    @my_dec
    def c(self):
        return 3

然后get_values()A实例的{'a-special-name': 1, 'b': 2, 'c': 3}应该返回class my_dec(object): def __init__(self, func, name=None): self.func = func self.name = name or func.__name__ self.func._some_flag = True def __get__(self, instance, cls=None): if instance is None: return self return self.func(instance) (订单当然无关紧要)

编辑:基于类的装饰器,但不能继承。知道如何使它继承继承但不必装饰类本身吗?

Tried this for monthly employee trend


SELECT
        dt.FullDateAlternateKey as 'Date'
    ,   count(1) as ActiveCount 
FROM DimDate dt
LEFT JOIN   (SELECT 'Active' as 'EmpStatus', * FROM DimEmployee) emp
    -- regular active employees
    ON (dt.FullDateAlternateKey between emp.StartDate and ISNULL(emp.EndDate,'9999-12-31'))
WHERE
    dt.FullDateAlternateKey = EOMONTH(dt.FullDateAlternateKey)
GROUP BY
        dt.FullDateAlternateKey
ORDER BY
        1;


also found CTE use for finding employee hierarchy

WITH DirectReports (ManagerID, EmployeeID, Title, DeptID, Level)
AS
(
-- Anchor member definition
    SELECT e.ParentEmployeeKey, e.EmployeeKey, e.Title, e.DepartmentName, 
        0 AS Level
    FROM DimEmployee AS e
    WHERE e.ParentEmployeeKey IS NULL
    UNION ALL
-- Recursive member definition
    SELECT e.ParentEmployeeKey, e.EmployeeKey, e.Title, e.DepartmentName,
        Level + 1
    FROM DimEmployee AS e
    INNER JOIN DirectReports AS d
        ON e.ParentEmployeeKey = d.EmployeeID
)
-- Statement that executes the CTE
SELECT ManagerID, EmployeeID, Title, DeptID, Level
FROM DirectReports
WHERE DeptID = 'Information Services' OR Level = 0



also, some good queries to analyze the sales data

-- Show each sales average for Group, Country, and Region all in one query
SELECT DISTINCT     
        t.SalesTerritoryGroup
    ,   t.SalesTerritoryCountry
    ,   t.SalesTerritoryRegion
    ,   AVG(s.SalesAmount) OVER(PARTITION BY t.SalesTerritoryGroup ) as 'GroupAvgSales'     
    ,   AVG(s.SalesAmount) OVER(PARTITION BY t.SalesTerritoryCountry ) as 'CountryAvgSales'
    ,   AVG(s.SalesAmount) OVER(PARTITION BY t.SalesTerritoryRegion ) as 'RegionAvgSales'   

FROM FactInternetSales s
JOIN DimSalesTerritory t ON
    s.SalesTerritoryKey = t.SalesTerritoryKey   
WHERE
        YEAR(s.OrderDate) = 2013
ORDER BY
        1,2,3

Use additional aggregations to understand more about product sales such as the distribution of sales etc..
SELECT 
        cat.EnglishProductCategoryName 'Category'
    ,   sub.EnglishProductSubcategoryName 'SubCategory'
    ,   count(1) 'Count' -- How many sales where there?
    ,   sum(s.SalesAmount) 'Sales' -- How much sales did we have?
    ,   avg(s.SalesAmount) 'Avg_SalesAmount' -- What was the Avg sale amount?
    ,   min(s.SalesAmount) 'Min_SaleAmount' -- What was the Min sale amount?
    ,   max(s.SalesAmount) 'Max_SaleAmount' -- What was the Max sale amount
FROM FactInternetSales s
LEFT JOIN DimProduct p ON s.ProductKey = p.ProductKey
LEFT JOIN DimProductSubcategory sub ON p.ProductSubcategoryKey = sub.ProductSubcategoryKey
LEFT JOIN DimProductCategory cat ON sub.ProductCategoryKey = cat.ProductCategoryKey
-- must use group by in order for aggregation to work properly
GROUP BY
        cat.EnglishProductCategoryName -- column aliases aren't allowed
    ,   sub.EnglishProductSubcategoryName
ORDER BY
        cat.EnglishProductCategoryName
    ,   sub.EnglishProductSubcategoryName

-- Calculate the customer acquisition funnel
SELECT
        c.FirstName
    ,   c.LastName
    ,   c.DateFirstPurchase
    ,   DATEDIFF(d,c.DateFirstPurchase,getdate()) as 'DaysSinceFirstPurchase' -- How long have they been a customer?
FROM DimCustomer c
ORDER BY 3 DESC


-- Calculate a Monthly average of customer tenure
SELECT
        EOMONTH(c.DateFirstPurchase) as 'MonthOfFirstPurchase' -- What month did they become a customer?
    ,   DATEDIFF(d,EOMONTH(c.DateFirstPurchase),getdate()) as 'DaysSinceFirstPurchase' -- How long have they been a customer?
    ,   COUNT(1) as 'CustomerCount' -- How manY customers are there for this month?
FROM DimCustomer c
GROUP BY EOMONTH(c.DateFirstPurchase)
ORDER BY 2 DESC

-- Show the top product Sub Categories for each year
SELECT      
        count(DISTINCT s.SalesOrderNumber) 'OrderCount' -- use 1 instead of a field for faster performance
    ,   RANK() OVER (PARTITION BY YEAR(s.OrderDate) ORDER BY sum(s.SalesAmount) DESC) 'SalesRank' 
    ,   sum(s.SalesAmount) 'TotalSales'
    ,   cat.EnglishProductCategoryName 'Category'
    ,   sub.EnglishProductSubcategoryName 'SubCategory' 
    ,   YEAR(s.OrderDate) 'Year'
FROM FactInternetSales s
INNER JOIN DimProduct p ON s.ProductKey = p.ProductKey
INNER JOIN DimProductSubcategory sub ON p.ProductSubcategoryKey = sub.ProductSubcategoryKey
INNER JOIN DimProductCategory cat ON sub.ProductCategoryKey = cat.ProductCategoryKey
-- must use group by in order for aggregation to work properly
GROUP BY
        cat.EnglishProductCategoryName -- column aliases aren't allowed
    ,   sub.EnglishProductSubcategoryName   
    ,   YEAR(s.OrderDate)

ORDER BY YEAR(s.OrderDate), SUM(s.SalesAmount) DESC;

-- first, create weekly sales totals
SELECT  SUM(s.SalesAmount) 'WeeklySales' 
    ,   DATEPART(ww, s.OrderDate) as 'WeekNum'
FROM    FactInternetSales s
WHERE   YEAR(s.OrderDate) = 2013
GROUP BY
        DATEPART(ww, s.OrderDate)
ORDER BY
        DATEPART(ww, s.OrderDate) ASC

-- use that subquery as our source and calculate the moving average
SELECT
        AVG(WeeklySales) OVER (ORDER BY WeekNum ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as AvgSales
    ,   WeeklySales as 'TotalSales'
    ,   WeekNum
FROM (
    SELECT  SUM(s.SalesAmount) 'WeeklySales' 
        ,   DATEPART(ww, s.OrderDate) as 'WeekNum'
    FROM    FactInternetSales s
    WHERE   YEAR(s.OrderDate) = 2013
    GROUP BY
            DATEPART(ww, s.OrderDate)
    ) AS s
GROUP BY
        WeekNum, WeeklySales
ORDER BY
        WeekNum ASC


-- Running Total
SELECT
        SUM(MonthlySales) OVER (PARTITION BY SalesYear ORDER BY SalesMonth ROWS UNBOUNDED PRECEDING) as YTDSales
    ,   MonthlySales as 'MonthlySales'
    ,   SalesYear
    ,   SalesMonth
FROM (
    SELECT  SUM(s.SalesAmount) 'MonthlySales' 
        ,   MONTH(s.OrderDate) as 'SalesMonth'
        ,   year(s.OrderDate) as 'SalesYear'
    FROM    FactInternetSales s
    GROUP BY
            MONTH(s.OrderDate)
        ,   year(s.OrderDate)
    ) AS s
GROUP BY
        SalesMonth, SalesYear, MonthlySales
ORDER BY
        SalesYear, SalesMonth ASC

-- Get Prev Year Sales
WITH MonthlySales (YearNum, MonthNum, Sales)
AS
(
    SELECT d.CalendarYear, d.MonthNumberOfYear, SUM(s.SalesAmount) 
    FROM DimDate d
    JOIN FactInternetSales s ON d.DateKey = s.OrderDateKey
    GROUP BY d.CalendarYear, d.MonthNumberOfYear
)
-- Get Current Year and join to CTE for previous year
SELECT 
        d.CalendarYear
    ,   d.MonthNumberOfYear
    ,   ms.Sales PrevSales
    ,   SUM(s.SalesAmount) CurrentSales
FROM DimDate d
JOIN FactInternetSales s ON d.DateKey = s.OrderDateKey
JOIN MonthlySales ms ON 
    d.CalendarYear-1 = ms.YearNum AND
    d.MonthNumberOfYear = ms.MonthNum
GROUP BY
        d.CalendarYear
    ,   d.MonthNumberOfYear
    ,   ms.Sales
ORDER BY
        1 DESC, 2 DESC


-- Now calculate the % change Year over Year
WITH MonthlySales (YearNum, MonthNum, Sales)
AS
(
    SELECT d.CalendarYear, d.MonthNumberOfYear, SUM(s.SalesAmount) 
    FROM DimDate d
    JOIN FactInternetSales s ON d.DateKey = s.OrderDateKey
    GROUP BY d.CalendarYear, d.MonthNumberOfYear
)
-- Get Current Year and join to CTE for previous year
SELECT 
        d.CalendarYear
    ,   d.MonthNumberOfYear
    ,   ms.Sales PrevSales
    ,   SUM(s.SalesAmount) CurrentSales
    ,   (SUM(s.SalesAmount) - ms.Sales) / SUM(s.SalesAmount) 'PctGrowth'
FROM DimDate d
JOIN FactInternetSales s ON d.DateKey = s.OrderDateKey
JOIN MonthlySales ms ON 
    d.CalendarYear-1 = ms.YearNum AND
    d.MonthNumberOfYear = ms.MonthNum
GROUP BY
        d.CalendarYear
    ,   d.MonthNumberOfYear
    ,   ms.Sales
ORDER BY
        1 DESC, 2 DESC

3 个答案:

答案 0 :(得分:0)

如果您可以自己定义装饰器,那么只需要它"标记"方法对象以某种方式:

q)select from t where name in searchNames
name   c1
---------
"jim"  0
"john" 1
"john" 2
然后,该类可以查找那些标记的方法;类似的东西:

def my_dec(method):
    method._this_be_decorated = True
    return method

这将返回一个可迭代的函数对象,您可以根据需要进一步处理。

答案 1 :(得分:0)

def my_dec(name):
    if callable(name):
        # name is callable – take its name
        func = name # no make the code more readable
        func.special_name = func.__name__
        return func
    else:
        # name is the name to give – add an inner layer of functions
        def inner(function_object):
            function_object.special_name = name
            return function_object
        return inner

class A():
    def get_values(self):
        # return a dict of special name to call result mapping for every class member that has a special_name.
        return {func.special_name: func(self) for func in self.__class__.__dict__.values() if hasattr(func, 'special_name')}
      # returned {'a-special-name': 1, 'b': 2}
    @my_dec('a-special-name')  # Ideally be able to also put optional name
    def a(self):
      return 1
    @my_dec
    def b(self):
      return 2
    def no_dec(self):
      return 42

应该做你想做的事。

答案 2 :(得分:0)

正如deceze所提到的,装饰者可以做任何他们想做的事情,因此没有可靠的通用答案。如果您“拥有”装饰器,您可以为其返回值添加特殊属性,即(Q& D py2.7示例):

def mydec(name=''):
    # py27 hack - for py3 you want nonlocal instead
    n = [name]

    def innerdec(func):
        # py27 hack - for py3 you want nonlocal instead
        name = n[0] or func.__name__
        def wrapper(*args, **kw):
            print("in mydec.wrapper for {}".format(name))
            return func(*args, **kw)
        wrapper.ismydec = True # so we know this is decorated by mydec
        wrapper.func = func # so we can get the original func
        wrapper.name = name
        return wrapper
    return innerdec

def collect_dec(cls):
      decorated = {}
      for attname in dir(cls):
          obj = getattr(cls, attname)
          if getattr(obj, "ismydec", False):
              decorated[obj.name] = obj.func
      cls._decorated_funcs = decorated
      return cls

@collect_dec
class A():
    def get_values(self):
        return {
            name:func(self) for name, func in self._decorated_funcs.items()
            }

    @mydec('a-special-name')  # Ideally be able to also put optional name
    def a(self):
      return 1

    @mydec() # no name
    def b(self):
      return 2


a = A()
print(a.get_values())

哪个输出:

{'a-special-name': 1, 'b': 2}